
// 6.2  创建对象

// 6.2.1 工厂模式
// 就是最经典的工厂设计模式

(function(){
	function createPerson(name,age,job){
		var o = new Object();
		o.name = name;
		o.age = age;
		o.job = job;
		o.sayName = function(){
			console.log(this.name);
		}
		return o;
	}

	var person1 = createPerson('Nicholas',29,'Software Engineer');
	var person2 = createPerson('Greg',27,'Doctor');
	console.log('==========6.2.1 工厂模式');
	person1.sayName();
	person2.sayName();
}());

// 6.2.2 构造函数模式

(function(){
	function Person(name,age,job){
		this.name = name;
		this.age = age;
		this.job = job;
		this.sayName = function(){
			console.log(this.name);
		}
	}
	
	var person1 = new Person('Nicholas',29,'Software Engineer');
	var person2 = new Person('Greg',27,'Doctor');

	console.log("------6.2.2 构造函数模式------");

	console.log(person1 instanceof Object);
	console.log(person1 instanceof Person);

	console.log(person2 instanceof Object);
	console.log(person2 instanceof Person);

	// 当做构造函数使用
	var person = new Person('Nicholas',29,'Software Engineer');
	person.sayName();	

	// 作为普通函数调用
	Person('Greg',27,'Doctor');
	sayName();

	// 在另一个对象作用域中调用
	var o = new Object();
	Person.call(o,'Kristen',25,'Nurse');
	o.sayName();

}());

// 上面的代码写法,会在每个实例重新创建一遍每个方法,我们可以使用构造函数外定义的方式解决,angular中也有这种写法
(function(){
	
	function Person(name,age,job){
		this.name = name;
		this.age = age;
		this.job = job;
		this.sayName = sayName;
	}

	function sayName(){
		console.log(this.name);
	}

	var person1 = new Person('Nicholas',29,'Software Engineer');
	var person2 = new Person('Greg',27,'Doctor');

	console.log('构造函数外定义函数');
	person1.sayName();
	person2.sayName();
}());


// 6.2.3 原型模式
(function(){
	function Person(){
	}

	Person.prototype.name = 'Nicholas';
	Person.prototype.age = 29;
	Person.prototype.job = 'Software Engineer';
	Person.prototype.sayName = function(){
		console.log(this.name);
	}

	console.log('------ 6.2.3 原型模式------');
	var person1 = new Person();
	person1.sayName();
	
	var person2 = new Person();
	console.log('sayName is the same ?: '+ (person1.sayName==person2.sayName));

	console.log('isPrototypeOf :'+ (Person.prototype.isPrototypeOf(person1)));
	console.log('es5 Obejct.getPrototypeOf :' + (Object.getPrototypeOf(person1) == Person.prototype));
	
}());

// 6.2.4 组合使用构造函数模式和原型模式
(function(){
	function Person(name,age,job){
		this.name = name;
		this.age = age;
		this.job = job;
		this.friends = ['Shelby','Court'];
	}

	Person.prototype = {
		constructor: Person,
		sayName: function(){
			console.log(this.name);
		}
	}

	var person1 = new Person('Nicholas',29,'Software Engineer');
	var person2 = new Person('Greg',27,'Doctor');

	console.log('------ 6.2.4 组合使用构造函数和原型模式------');
	person1.friends.push('Van');
	console.log(person1.friends);
	console.log(person2.friends);
	console.log( person1.friends === person2.friends );
	console.log( person1.sayName === person2.sayName );

}());

// 6.2.5 动态原型模式
// 构造方法中,往原型添加方法前,先校验之前是否存在
(function(){
	function Person(name,age,job){
		// 属性
		this.name = name;
		this.age = age;
		this.job = job;

		// 先校验方法是否已经定义
		if( typeof this.sayName != 'function' ){
			Person.prototype.sayName = function(){
				console.log(this.name);
			}
		}
	}

	console.log('------------6.2.5 动态原型模式---');
	var friend = new Person('Nicholas',29,'Software Engineer');
	friend.sayName();

}());

// 6.2.6 寄身构造函数模式
(function(){
	function Person(name,age,job){
		var o = new Object();
		o.name = name;
		o.age = age;
		o.job = job;
		o.sayName = function(){
			console.log(this.name);
		}
		return o;
	}

	console.log('---------------6.2.6 寄身构造函数模式--- ');
	var friend = new Person('Nicholas',29,'Software Engineer');
	friend.sayName();
}());


// 6.2.7 稳妥构造函数模式
// 其实是利用闭包来替换对象的概念
(function(){
	function Person(name,age,job){
		// 创建需要返回的对象
		var o = new Object();

		// 定义私有变量和函数
		
		// 添加公共方法
		o.sayName = function(){
			console.log(name);
		}

		return o;
	}
	console.log('---------------6.2.7 稳妥构造函数模式--- ');
	var friend = new Person('Nicholas',29,'Software Engineer');
	friend.sayName();
}());


// 6.3 继承
// 6.3.1 原型链
console.log('-------------6.3.1 原型链 ----');
(function(){
	function SuperType(){
		this.property = true;
	}

	SuperType.prototype.getSuperValue = function(){
		return this.property;
	}

	function SubType(){
		this.subProperty = false;
	}

	// 这样会导致丢失constructor
	SubType.prototype = new SuperType();

	SubType.prototype.getSubValue = function(){
		return this.subProperty;
	}

	console.log('=====基础原型链实现继承');
	var instance = new SubType();
	console.log(instance.getSuperValue());

}());

console.log('-------------6.3.2 借用构造函数-------');
// 这种写法,原型中定义的方法不能继承,只能通过构造函数定义
(function(){
	function SuperType(){
		this.colors = ['red','blue','green'];
	}

	SuperType.prototype.getMe = function(){
		return 'getMe: get caught ';
	}

	function SubType(){
		SuperType.call(this);
	}

	var instance1 = new SubType();
	instance1.colors.push('black');
	console.log( instance1.colors.join(',') );

	var instance2 = new SubType();
	console.log( instance2.colors.join(',') );
	// getMe 定义在原型中,不能继承
	//console.log( instance2.getMe());
}());

console.log('-------------6.3.3 组合继承-----');
// 借用构造方法继承属性;原型链继承方法
(function(){
	function SuperType(name){
		this.name = name;
		this.colors = ['red','blue','green'];
	}

	SuperType.prototype.sayName = function(){
		console.log('sayName: '+ this.name);
	}

	function SubType(name,age){
		SuperType.call(this,name);
		this.age = age;
	}

	SubType.prototype = new SuperType();

	SubType.prototype.sayAge = function(){
		console.log('say: '+ this.age);
	}

	var instance1 = new SubType('Nicholas',29);
	instance1.colors.push('black');
	console.log( instance1.colors.join(',') );
	instance1.sayName();
	instance1.sayAge();

	var instance2 = new SubType('Greg',27);
	console.log( instance2.colors.join(',') );
	instance2.sayName();
	instance2.sayAge();

}());

console.log('-----------------6.3.4 原型式继承--------');
// 可以使用es5的Object.create实现
(function(){
	function object(o){
		function F(){}
		F.prototype = o;
		return new F();
	}

	var person = {
		name: 'Nicholas',
		friends: ['Shelby','Court','Van']
	}

	var person1 = object(person);
	person1.name = 'Greg';
	person1.friends.push('Rob');

	var person2 = object(person);
	person2.name = 'Linda';
	person2.friends.push('Barbie');

	console.log( person.friends.join(',') );

	var person3 = Object.create(person);
	console.log( person.friends.join(',') );
	
}());


console.log('----------------6.3.5 寄身式继承-------');
// 与原型式继承的差别是,在函数内添加功能增强
(function(){
	function object(o){
		function F(){}
		F.prototype = o;
		return new F();
	}

	function create(o){
		var clone = object(o);
		clone.sayHi = function(){
			console.log('hi');
		}
		return clone;
	}

}());

console.log('-----------------6.3.6 寄身组合式继承----');
// 在组合式继承基础上,在函数中进行功能增强
